<?php
	require_once(dirname(__FILE__)."/../../config.php");
	require_once(dirname(__FILE__)."/../../debug.php");
	define("TYPE_ADD",			"add");		
	define("TYPE_UPDATE",		"update");
	define("TYPE_KEEP",			"keep");
	define("OLD_FODLER_NAME",		"widgets_old");
	define("OLD_IMG_FODLER_NAME",		"img_old");
	define("OLD_LAYOUT_FODLER_NAME",		"layout_old");
	define("PRODUCT_OLD_FODLER_NAME",		"product_old");
	define("OLD_WIDGETLIST_NAME",		"widgetList_old.js");
	define("WIDGETLIST_NAME",		"widgetList.js");
	define("OLD_LAYOUTLIST_NAME",		"layoutList_old.js");
	define("LAYOUTLIST_NAME",		"layoutList.js");
	define("PID_NAME",		"widgetpool.pid");
	
	define("ERROR_SUCCESS",			0);		
	define("ERR_ANOTHER_PROCESS_IS_RUNNING",				1);
	define("ERR_OLD_WIDGET_SUMMARY_NOT_EXIST",			2);
	define("ERR_OLD_WIDGET_SUMMARY_LOAD_FAIL",				3);
	define("ERR_NEW_WIDGET_SUMMARY_NOT_EXIST",		4);
	define("ERR_NEW_WIDGET_SUMMARY_LOAD_FAIL",		5);
	define("ERR_LANG_XML_LOAD_FAIL",	6);
	define("ERR_UPD_WIDGETLIST",			7);

/*
 * WidgetFramework WidgetPool
 * Created: 200910 (Roger Wang)
 *
 */
class WFWidgetPool {
	// Product Info XML DOM
	private	$ProductInfoDOM;
	
	// Product Info XML file
	private	$ProductInfoFile;
	
	//Widget new folder
	private $widget_new_folder;
		
	// error handling
	private $errMessage = "";
	
	// Constructor
	public function __construct() {
		global $wfconf_WFHome;
		mydebug_log("[WIDGETPOOL] __construct()");
		if(!class_exists('WF')){
		    require_once(dirname(__FILE__).'/../init.php');
		}
	    $this->widget_new_folder = WF::getDocumentRoot().'/repository/widgets_new'; 
	}
	
	public function check_pool() {
		if (file_exists($this->widget_new_folder))
			return TRUE;
    else
    	return FALSE;	
	}
	
	public function compare_WidgetSummary() {
		$mymutex=new WFMutex();
		if(!$mymutex->isRunning())
		{
			$oldWidgetSummaryFile=$GLOBALS['wfconf_WFHome'].'/'.$GLOBALS['wfconf_dir_modules']."/WidgetSummary.xml";
			$oldWidgetSummaryDOM=new DOMDocument();
			$newWidgetSummaryFile=$this->widget_new_folder.'/'.$GLOBALS['wfconf_dir_modules']."/WidgetSummary.xml";
			$newWidgetSummaryDOM=new DOMDocument();
			$compareResultDOM=new DOMDocument();
			if(!file_exists($oldWidgetSummaryFile))
			{
					mydebug_log("[WFWIDGETPOOL] compare_WidgetSummary() file ".$oldWidgetSummaryFile." doesn't exist");
					$this->errMessage = "file ".$oldWidgetSummaryFile." doesn't exist";
					return ERR_OLD_WIDGET_SUMMARY_NOT_EXIST;			
			}
		
			if (!$oldWidgetSummaryDOM->load($oldWidgetSummaryFile))
			{
					mydebug_log("[WFWIDGETPOOL] compare_WidgetSummary() load ".$oldWidgetSummaryFile." fail");
					$this->errMessage = "load ".$oldWidgetSummaryFile." fail";
					return ERR_OLD_WIDGET_SUMMARY_LOAD_FAIL;
			}
			if(!file_exists($newWidgetSummaryFile))
			{
					mydebug_log("[WFWIDGETPOOL] compare_WidgetSummary() file ".$newWidgetSummaryFile." doesn't exist");
					$this->errMessage = "file ".$newWidgetSummaryFile." doesn't exist";
					return ERR_NEW_WIDGET_SUMMARY_NOT_EXIST;			
			}
		
			if (!$newWidgetSummaryDOM->load($newWidgetSummaryFile))
			{
					mydebug_log("[WFWIDGETPOOL] compare_WidgetSummary() load ".$newWidgetSummaryFile." fail");
					$this->errMessage = "load ".$newWidgetSummaryFile." fail";
					return ERR_NEW_WIDGET_SUMMARY_LOAD_FAIL;
			}
			$this->doCompare($oldWidgetSummaryDOM,$newWidgetSummaryDOM,$compareResultDOM);
			$returncode=$this->doAction($compareResultDOM);
			if($returncode!=ERROR_SUCCESS)
				return $returncode;		
			$this->switchFolderName();
		}
		else
		{
					$this->errMessage = "Another update process is running";
					return ERR_ANOTHER_PROCESS_IS_RUNNING;			
		}
		return ERROR_SUCCESS;
	}
	
	function createElement(&$domObj, $tag_name, $value = NULL, $attributes = NULL)
	{
    $element = ($value != NULL ) ? $domObj->createElement($tag_name, $value) : $domObj->createElement($tag_name);
    if( $attributes != NULL )
    {
        foreach ($attributes as $attr=>$val)
        {
            $element->setAttribute($attr, $val);
        }
    }
    return $element;
	}

	function UpdateCompareResultDom(&$compareResultDOM,&$newWidgetNode,$type)
	{
				if($newWidgetNode->getElementsByTagName('language')->length==1)
				{
					$elm=$this->createElement($compareResultDOM,'action','',array('id'=>$newWidgetNode->getAttribute('id'),'type'=>$type,'category'=>$newWidgetNode->getAttribute('category'),'icon'=>$newWidgetNode->getAttribute('icon')));
					$compareResultDOM->appendChild($elm);
					$node = $compareResultDOM->importNode($newWidgetNode->getElementsByTagName('language')->item(0), true);
					$elm->appendChild($node);
				}		
	}
	
	function doCompare(&$oldWidgetSummaryDOM,&$newWidgetSummaryDOM,&$compareResultDOM) {
		$oldWidgetNodeList = $oldWidgetSummaryDOM->getElementsByTagName('Widget');
		$newWidgetNodeList = $newWidgetSummaryDOM->getElementsByTagName('Widget');

		foreach( $newWidgetNodeList as $newWidgetNode)
		{
			$found=false;
			foreach( $oldWidgetNodeList as $oldWidgetNode)
			{
				if($oldWidgetNode->getAttribute('id')==$newWidgetNode->getAttribute('id'))
				{
					$found=true;
					//new widget version is newer
					if(version_compare($newWidgetNode->getAttribute('version'),$oldWidgetNode->getAttribute('version'))===1)
					{
						mydebug_log($newWidgetNode->getAttribute('id')." ".$newWidgetNode->getAttribute('version')." ".$newWidgetNode->hasChildNodes()." new widget version is newer than current one\n");
						$this->UpdateCompareResultDom($compareResultDOM,$newWidgetNode,TYPE_UPDATE);
					}
					elseif(version_compare($newWidgetNode->getAttribute('version'),$oldWidgetNode->getAttribute('version'))===0)
					{
						mydebug_log($newWidgetNode->getAttribute('id')." ".$newWidgetNode->getAttribute('version')." ".$newWidgetNode->hasChildNodes()." version is the same\n");
						$this->UpdateCompareResultDom($compareResultDOM,$newWidgetNode,TYPE_KEEP);
					}
					else
					{
						mydebug_log($newWidgetNode->getAttribute('id')." ".$newWidgetNode->getAttribute('version')." ".$newWidgetNode->hasChildNodes()." new widget version is less than current one\n");
					}
				}
			}
			if(!$found)
			{
				mydebug_log($newWidgetNode->getAttribute('id')." ".$newWidgetNode->getAttribute('version')." ".$newWidgetNode->hasChildNodes()." this is a brand new widget\n");
				$this->UpdateCompareResultDom($compareResultDOM,$newWidgetNode,TYPE_ADD);		
			}
		}
		mydebug_log($compareResultDOM->saveXML());
	}

	function rmdir_recurse($path) 
	{ 
    	$path= rtrim($path, '/').'/'; 
    	$handle = opendir($path); 
    	for (;false !== ($file = readdir($handle));) 
        	if($file != "." and $file != ".." ) 
        	{ 
            	$fullpath= $path.$file; 
            	if( is_dir($fullpath) ) 
                	$this->rmdir_recurse($fullpath); 
            	else 
                	unlink($fullpath); 
    		} 
    	closedir($handle); 
    	rmdir($path); 
	}
	
	function switchFolderName()
	{
		//remove old directories
		if(file_exists($GLOBALS['wfconf_WFHome'].'/'.OLD_FODLER_NAME))
			$this->rmdir_recurse($GLOBALS['wfconf_WFHome'].'/'.OLD_FODLER_NAME);
		if(file_exists($GLOBALS['wfconf_WFHome'].'/includes/'.PRODUCT_OLD_FODLER_NAME))
			$this->rmdir_recurse($GLOBALS['wfconf_WFHome'].'/includes/'.PRODUCT_OLD_FODLER_NAME);
		if(file_exists($GLOBALS['wfconf_WFHome'].'/'.OLD_IMG_FODLER_NAME))
			$this->rmdir_recurse($GLOBALS['wfconf_WFHome'].'/'.OLD_IMG_FODLER_NAME);
		if(file_exists($GLOBALS['wfconf_WFHome'].'/'.OLD_LAYOUT_FODLER_NAME))
			$this->rmdir_recurse($GLOBALS['wfconf_WFHome'].'/'.OLD_LAYOUT_FODLER_NAME);
		if(file_exists($GLOBALS['wfconf_WFHome'].'/'.OLD_LAYOUTLIST_NAME))
			unlink($GLOBALS['wfconf_WFHome'].'/'.OLD_LAYOUTLIST_NAME);
		//backup and replace widgets folder
		rename($GLOBALS['wfconf_WFHome'].'/'.$GLOBALS['wfconf_dir_modules'],$GLOBALS['wfconf_WFHome'].'/'.OLD_FODLER_NAME);
		rename($this->widget_new_folder.'/'.$GLOBALS['wfconf_dir_modules'],$GLOBALS['wfconf_WFHome'].'/'.$GLOBALS['wfconf_dir_modules']);
		//backup and replace product folder 
		rename($GLOBALS['wfconf_WFHome'].'/includes/product',$GLOBALS['wfconf_WFHome'].'/includes/'.PRODUCT_OLD_FODLER_NAME);
		rename($this->widget_new_folder.'/product',$GLOBALS['wfconf_WFHome'].'/includes/product');
		//backup and replace img folder
		rename($GLOBALS['wfconf_WFHome'].'/img',$GLOBALS['wfconf_WFHome'].'/'.OLD_IMG_FODLER_NAME);
		rename($this->widget_new_folder.'/img',$GLOBALS['wfconf_WFHome'].'/img');
		//backup and replace layout folder
		rename($GLOBALS['wfconf_WFHome'].'/layout',$GLOBALS['wfconf_WFHome'].'/'.OLD_LAYOUT_FODLER_NAME);
		rename($this->widget_new_folder.'/layout',$GLOBALS['wfconf_WFHome'].'/layout');
	  //backup and replace layout.js file
		rename($GLOBALS['wfconf_WFHome'].'/'.LAYOUTLIST_NAME,$GLOBALS['wfconf_WFHome'].'/'.OLD_LAYOUTLIST_NAME);
		rename($this->widget_new_folder.'/'.LAYOUTLIST_NAME,$GLOBALS['wfconf_WFHome'].'/'.LAYOUTLIST_NAME);
		//remove new folder
		rmdir($this->widget_new_folder);
	}

	function doAction(&$compareResultDOM) {
			$returncode=$this->UpdateWidgetList($compareResultDOM);
			if($returncode!=ERROR_SUCCESS)
				return $returncode;
			$compareResultNodeList = $compareResultDOM->getElementsByTagName('action');
			foreach( $compareResultNodeList as $compareResultNode)
			{
				switch ($compareResultNode->getAttribute('type')) {
    			case TYPE_ADD:
        		mydebug_log($compareResultNode->getAttribute('id')." ".$compareResultNode->getAttribute('type'));
        		$returncode=$this->UpdateLanguageXML($compareResultNode,true);
        		break;
    			case TYPE_UPDATE:
    				mydebug_log($compareResultNode->getAttribute('id')." ".$compareResultNode->getAttribute('type'));
    				$returncode=$this->UpdateLanguageXML($compareResultNode,false);
        		break;
        	case TYPE_KEEP:
    				//$this->UpdateLanguageXML($compareResultNode);
        		break;
    			default:
        		$this->errMessage = "Unknown action type";
				}
			}
			return $returncode;
	}
	
	/**
	 *	\brief		Update languegs/XX.xml
	 *
	 *	\param[in]	WidgetInfoDOM		widget_info.xml DOM object
	*/
	function UpdateLanguageXML(&$compareResultNode,$isAdd)
	{
		$returncode=ERROR_SUCCESS;
		$WidgetNodeList = $compareResultNode->getElementsByTagNameNS($GLOBALS['wfconf_product_ns'], 'language');
		
		$LangNode = $WidgetNodeList->item(0)->firstChild;
		while ($LangNode != NULL)
		{
			if ($LangNode->nodeType == XML_ELEMENT_NODE)
			{
				$returncode=$this->UpdateOneLanguageXML($LangNode,$isAdd);
				if($returncode!=ERROR_SUCCESS)
					break;
			}
			
			$LangNode = $LangNode->nextSibling;
		}
		return $returncode;
	}
	
	/**
	 *	\brief		Update one $LangID.xml
	 *
	 *	\param[in]	$LangNode
	*/
	function UpdateOneLanguageXML(&$LangNode,$isAdd)
	{
		// Load XX.xml
		$LangDOM = new DOMDocument();
		if (!$LangDOM->load($GLOBALS['wfconf_dir_lang'].'/'.$LangNode->nodeName.'.xml'))
			return ERR_LANG_XML_LOAD_FAIL;
		
		$translationsNodeList = $LangDOM->getElementsByTagName('translations');
		$xpath = new DOMXpath($LangDOM);
		
		$StringNode = $LangNode->firstChild;
		while ($StringNode != NULL)
		{
			if ($StringNode->nodeType == XML_ELEMENT_NODE)
			{
				$xpathString = '/translations/'.$StringNode->nodeName.'[@id=\''.$StringNode->attributes->getNamedItem('id')->nodeValue.'\']';
				$QueryNodeList = $xpath->query($xpathString);
				
				if($isAdd)
				{
					foreach ($QueryNodeList as $domElement)
					{
						$domElement->parentNode->removeChild($domElement);
					}
				
					$StringElement = $LangDOM->createElement($StringNode->nodeName, $StringNode->nodeValue);
					foreach ($StringNode->attributes as $attrName => $attrNode) 
						$StringElement->setAttribute($attrNode->name, $attrNode->value);
					$translationsNodeList->item(0)->appendChild($StringElement);
				}
				else
				{
					if($QueryNodeList->length>1)
					{
						$count=0;
						foreach ($QueryNodeList as $domElement)
						{
							if($count!=0)
							{
								$domElement->parentNode->removeChild($domElement);					
							}
							$count++;
						}
						$QueryNodeList->item(0)->nodeValue=$StringNode->nodeValue;
					}
					elseif($QueryNodeList->length==1)
					{
						$QueryNodeList->item(0)->nodeValue=$StringNode->nodeValue;
					}
					else
					{
						$StringElement = $LangDOM->createElement($StringNode->nodeName, $StringNode->nodeValue);
						foreach ($StringNode->attributes as $attrName => $attrNode) 
							$StringElement->setAttribute($attrNode->name, $attrNode->value);
						$translationsNodeList->item(0)->appendChild($StringElement);
					}			
				}				
			}
			$StringNode = $StringNode->nextSibling;
		}		
		$LangDOM->save($GLOBALS['wfconf_dir_lang'].'/'.$LangNode->nodeName.'.xml');
		
		return ERROR_SUCCESS;
	}
	

	/**
	 *	\brief		Update widgetList.js
	 *
	 *	\param[in]	WidgetInfoDOM		compare Result DOM object
	*/
	function UpdateWidgetList(&$WidgetInfoDOM)
	{
		// backup original file
		copy($GLOBALS['wfconf_WFHome']."/".WIDGETLIST_NAME,$GLOBALS['wfconf_WFHome']."/".OLD_WIDGETLIST_NAME);

		$widgetList = file_get_contents($GLOBALS['wfconf_WFHome']."/".WIDGETLIST_NAME);
		if ($widgetList == FALSE)
			return ERR_UPD_WIDGETLIST;
			
		$posStart = strpos($widgetList, "=") + 1;		
		$posEnd = strrpos($widgetList, ";");
		$widgetList = substr($widgetList, $posStart, $posEnd - $posStart);
		$arWidgetList = json_decode($widgetList);

		
		$compareResultNodeList = $WidgetInfoDOM->getElementsByTagName('action');
		$lastupdateitme=time()*1000;
		
		foreach ($arWidgetList->{'widgets'} as $key => $value)
		{
			$found=false;
			foreach ($compareResultNodeList as $compareResultNode)
			{
				if ($value->{'name'} == $compareResultNode->getAttribute('id'))
				{
					if($compareResultNode->getAttribute('type')!=TYPE_KEEP)
					{
						unset($arWidgetList->{'widgets'}[$key]);
					}
					$found=true;
					break;
				}
			}
			if(!$found)
			{
				unset($arWidgetList->{'widgets'}[$key]);
			}
		}

		foreach ($compareResultNodeList as $compareResultNode)
		{
			if($compareResultNode->getAttribute('type')!=TYPE_KEEP) 
			{
				array_unshift($arWidgetList->{'widgets'},
				 array(
				'category'	=> $compareResultNode->getAttribute('category'),
				//'icon' 		=> $compareResultNode->getAttribute('icon'),
				'name' 		=>  $compareResultNode->getAttribute('id'),
				'icon'	=> $compareResultNode->getAttribute('icon'),
				'lastupdate'	=> (string)$lastupdateitme));
		  }
		}			
		if (!($fp = fopen($GLOBALS['wfconf_WFHome']."/".WIDGETLIST_NAME, "w")))
			return ERR_UPD_WIDGETLIST;
			
		fprintf($fp, "var widgetList ={\n");
		fprintf($fp, "\t\"widgets\": [\n");
		
		$WidgetCount = count($arWidgetList->{'widgets'});
		$idx = 0;
		
		foreach ($arWidgetList->{'widgets'} as $key => $value)
		{
			fprintf($fp, "\t\t%s%s\n", json_encode($value), ($idx++ < $WidgetCount - 1) ? "," : "");
		}
		
		fprintf($fp, "\t]\n");
		fprintf($fp, "};\n");
			
		fclose($fp);		

		return ERROR_SUCCESS;
	}

	/*
	 * Error handling
	 */
	public function isFailed() {
		if( $this->errMessage != "" ) {
			return TRUE;
		}
		return FALSE;
	}
	
	public function getErrMessage() {
		return $this->errMessage;
	}
}